﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Net;
using System.Text;
using Thor.Common;

namespace Thor.Domain.Configuration
{
    /// <summary>
    /// Configuration settings for Thor.
    /// </summary>
    public class Settings : ThorDomainObjectBase, ISettings
    {
        #region Constants

        private const string USEBOOKINGAGENT = "UseBookingAgent";
        private const string BOOKINGAGENTEMAIL = "BookingAgentEmail";
        private const string CALENDARPROVIDERURI = "CalendarProviderUri";
        private const string USERNAME = "UserName";
        private const string PASSWORD = "Password";
        private const string RETRYCOUNT = "RetryCount";
        private const string RETRYINTERVAL = "RetryInterval";
        private const string LOCKOUTDURATION = "LockoutDuration";
        private const string SETTINGSID = "SettingsId";
        private const string ASSEMBLYNAME = "AssemblyName";
        private const string ASSEMBLYTYPE = "AssemblyType";
        private const string SERVERTIMEZONE = "ServerTimeZone";

        #endregion

        #region Fields

        private bool _useBookingAgent = false;
        private string _bookingAgentEmail = string.Empty;
        private string _calendarProviderUri = string.Empty;
        private string _userName = string.Empty;
        private string _password = string.Empty;
        private int _retryCount;
        private int _retryInterval;
        private int _lockoutDuration;
        private int _settingsId = 1;
        private string _assemblyName = string.Empty;
        private string _assemblyType = string.Empty;
        private string _serverTimeZone = string.Empty;
        private bool _isEncrypted = false;
        private Settings _cache;

        #endregion

        #region Constructors

        public Settings() : base() { }

        public Settings(bool isEncrypted)
            : base()
        {
            _isEncrypted = isEncrypted;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Whether or not a booking agent is to be used
        /// to book appointments on a calendar.
        /// </summary>
        public bool UseBookingAgent 
        {
            get { return _useBookingAgent; }
            set
            {
                if (_useBookingAgent != value)
                {
                    _useBookingAgent = value;
                    OnPropertyChanged(USEBOOKINGAGENT);
                }
            }
        }

        /// <summary>
        /// The email address of the booking agent to sent
        /// appointment requests to in the case where
        /// UseBookingAgent == true.
        /// </summary>
        public string BookingAgentEmail 
        {
            get { return _bookingAgentEmail; }
            set
            {
                if (_bookingAgentEmail != value)
                {
                    _bookingAgentEmail = value;
                    OnPropertyChanged(BOOKINGAGENTEMAIL);
                }
            }
        }

        /// <summary>
        /// The uri of the calendar provider.
        /// </summary>
        [Required]
        public string CalendarProviderUri 
        {
            get { return _calendarProviderUri; }
            set
            {
                if (_calendarProviderUri != value)
                {
                    _calendarProviderUri = value;
                    OnPropertyChanged(CALENDARPROVIDERURI);
                }
            }
        }


        /// <summary>
        /// Username for authentication.
        /// </summary>
        [Required]
        public string UserName
        {
            get { return _userName; }
            set
            {
                if (_userName != value)
                {
                    _userName = value;
                    OnPropertyChanged(USERNAME);
                }
            }
        }

        /// <summary>
        /// Password for authentication.
        /// </summary>
        [Required]
        public string Password
        {
            get { return _password; }
            set
            {
                if (_password != value)
                {
                    _password = value;
                    OnPropertyChanged(PASSWORD);
                }
            }
        }

        /// <summary>
        /// The number of times a user can pass bad credentials into the
        /// application before being locked out.
        /// </summary>
        /// <remarks>
        /// This works in tandem with RetryDuration and LockoutDuration
        /// (i.e. a user can pass
        /// bad credentials into the application five times within an hour
        /// before being locked out.)
        /// </remarks>
        [Required]
        public int RetryCount 
        {
            get { return _retryCount; }
            set
            {
                if (_retryCount != value)
                {
                    _retryCount = value;
                    OnPropertyChanged(RETRYCOUNT);
                }
            }
        }

        /// <summary>
        /// The duration (in minutes) a user can pass in bad
        /// credentials before being locked out.
        /// </summary>
        /// <remarks>
        /// This works in tandem with RetryDuration and LockoutDuration
        /// (i.e. a user can pass
        /// bad credentials into the application five times within an hour
        /// before being locked out.)
        /// </remarks>
        [Required]
        public int RetryInterval 
        {
            get { return _retryInterval; }
            set
            {
                if (_retryInterval != value)
                {
                    _retryInterval = value;
                    OnPropertyChanged(RETRYINTERVAL);
                }
            }
        }

        /// <summary>
        /// The duration (in minutes) a user is locked out.
        /// </summary>
        /// <remarks>
        /// This works in conjunctions with the RetryCount and RetryInterval
        /// properties (i.e. if a user passes in bad credential five times
        /// within an hour, then the user is locked out for an hour.)
        /// </remarks>
        [Required]
        public int LockoutDuration 
        {
            get { return _lockoutDuration; }
            set
            {
                if (_lockoutDuration != value)
                {
                    _lockoutDuration = value;
                    OnPropertyChanged(LOCKOUTDURATION);
                }
            }
        }


        [Required]
        [Key]
        public int SettingsId
        {
            get { return _settingsId; }
            set
            {
                if (_settingsId != value)
                {
                    _settingsId = value;
                    OnPropertyChanged(SETTINGSID);
                }
            }
        }

        public string AssemblyName
        {
            get { return _assemblyName; }
            set
            {
                if (_assemblyName != value)
                {
                    _assemblyName = value;
                    OnPropertyChanged(ASSEMBLYNAME);
                }
            }
        }

        public string AssemblyType
        {
            get { return _assemblyType; }
            set
            {
                if (_assemblyType != value)
                {
                    _assemblyType = value;
                    OnPropertyChanged(ASSEMBLYTYPE);
                }
            }
        }

        public string ServerTimeZone
        {
            get { return _serverTimeZone; }
            set
            {
                if (_serverTimeZone != value)
                {
                    _serverTimeZone = value;
                    OnPropertyChanged(SERVERTIMEZONE);
                }
            }
        }

        public bool IsEncrypted
        {
            get { return _isEncrypted; }
            private set { _isEncrypted = value; }
        }

        #endregion

        #region Methods

        public void Encrypt()
        {
            if (!IsEncrypted)
            {
                Encryptor encryptor = new Encryptor();
                encryptor.Encrypt(this);
                IsEncrypted = true;
            }
        }

        public void Decrypt()
        {
            if (IsEncrypted)
            {
                Decryptor decryptor = new Decryptor();
                decryptor.Decrypt(this);
                IsEncrypted = false;
            }
        }

        public override void BeginEdit()
        {
            _cache = new Settings();
            _cache.BookingAgentEmail = this.BookingAgentEmail;
            _cache.CalendarProviderUri = this.CalendarProviderUri;
            _cache.UserName = this.UserName;
            _cache.Password = this.Password;
            _cache.LockoutDuration = this.LockoutDuration;
            _cache.RetryCount = this.RetryCount;
            _cache.RetryInterval = this.RetryInterval;
            _cache.UseBookingAgent = this.UseBookingAgent;
            _cache.SettingsId = this.SettingsId;
            _cache.AssemblyName = this.AssemblyName;
            _cache.AssemblyType = this.AssemblyType;
            _cache.ServerTimeZone = this.ServerTimeZone;
        }

        public override void CancelEdit()
        {
            this.BookingAgentEmail = _cache.BookingAgentEmail;
            this.CalendarProviderUri = _cache.CalendarProviderUri;
            this.UserName = _cache.UserName;
            this.Password = _cache.Password;
            this.LockoutDuration = _cache.LockoutDuration;
            this.RetryCount = _cache.RetryCount;
            this.RetryInterval = _cache.RetryInterval;
            this.UseBookingAgent = _cache.UseBookingAgent;
            this.SettingsId = _cache.SettingsId;
            this.AssemblyName = _cache.AssemblyName;
            this.AssemblyType = _cache.AssemblyType;
            this.ServerTimeZone = _cache.ServerTimeZone;
        }

        public override void EndEdit()
        {
            _cache = null;
        }

        #endregion
    }
}
 